<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
    <title>私聊聊天室</title>
    <script src="/socket.io/socket.io.js"></script>
    <!-- 引入样式文件 -->
    <link rel="stylesheet" href="https://unpkg.com/vant@2.12/lib/index.css" />

    <!-- 引入 Vue 和 Vant 的 JS 文件 -->
    <script src="./vue2.2.0.js"></script>
    <script src="https://unpkg.com/vant@2.12/lib/vant.min.js"></script>

    <style>
        :root { --vh: 1vh; }
        * { box-sizing: border-box; margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
        html, body { height: 100%; overflow: hidden; }
        #app { height: calc(var(--vh, 1vh) * 100); display: flex; flex-direction: column; }

        .login {
            position: fixed; inset: 0;
            display: flex; align-items: center; justify-content: center;
            background: #f0f0f0;
        }

        .login__form {
            background: white; width: 90%; max-width: 360px; padding: 30px;
            border-radius: 10px; box-shadow: 0 4px 20px rgba(0,0,0,0.1);
        }

        .login__form h2 { margin-bottom: 20px; font-size: 18px; }
        .login__form input, .login__form button {
            width: 100%; padding: 10px; font-size: 15px; margin-bottom: 15px;
        }

        .login__form input {
            border: 1px solid #ccc; border-radius: 8px; outline: none;
        }

        .login__form input:focus {
            border-color: #2d8cf0; box-shadow: 0 0 0 2px rgba(45, 140, 240, 0.2);
        }

        .login__form button {
            background: #2d8cf0; border: none; color: white; border-radius: 8px; cursor: pointer;
        }

        .chat__header {
            background: #2d8cf0; color: white; padding: 12px; font-weight: bold;
            display: flex; justify-content: space-between; align-items: center;
        }

        .chat__main {
            flex: 1; display: flex; overflow: hidden;
        }

        .chat__sidebar {
            width: 130px; background: #fff; border-right: 1px solid #ccc; position: relative;
        }

        .chat__sidebar h3 {
            font-size: 14px; padding: 10px; border-bottom: 1px solid #eee;
        }

        .chat__userlist {
            overflow-y: auto; height: calc(100% - 40px);
        }

        .chat__user {
            padding: 8px; font-size: 14px; border-bottom: 1px solid #eee; cursor: pointer;
        }

        .chat__user.active { background: #e0e0e0; }

        .chat_content_empty{
            position: relative;
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: center;
        }

        .chat__sidebar-footer {
            position: absolute;
            bottom: 10px;
            margin: 0 auto;
            width: 100%;
            padding: 0 10px;
        }
        .chat__disclaimer, .chat__copyright {
            font-size: 13px;
            text-align: center;
            color: #999;
        }

        .chat__content {
            flex: 1; display: flex; flex-direction: column;

        }

        .chat__content_inner{
            flex: 1; overflow-y: auto;
            display: flex; flex-direction: column;
        }

        .chat__messages {
            flex: 1; overflow-y: auto; padding: 10px;
            display: flex; flex-direction: column;background: #f9f9f9;
        }

        .message {
            max-width: 80%; margin: 5px 0; font-size: 14px; display: flex; flex-direction: column;
        }

        .message span {
            display: inline-block; padding: 6px 10px; border-radius: 10px;
            word-wrap: break-word; white-space: pre-wrap; overflow-wrap: anywhere; max-width: 100%;
        }

        .message .time { font-size: 11px; color: #999; margin-top: 3px; text-align: right }

        .my-message { align-self: flex-end; }
        .my-message span { background: #dcf8c6; align-self: flex-end}

        .other-message { align-self: flex-start; }
        .other-message span { background: #fff; align-self: flex-start}
        .other-message .time { align-self: flex-start}

        .chat__input {
            display: flex; padding: 10px; background: white; border-top: 1px solid #ccc;
        }

        .chat__input input {
            flex: 1; padding-left: 8px; border-radius: 20px; border: 1px solid #ccc; margin-right: 8px;
        }

        .chat__input button {
            background: #2d8cf0; color: white; border: none; border-radius: 20px; padding: 10px 16px;
        }
    </style>
</head>
<body>
<div id="app">
    <!-- 登录 -->
    <div class="login" v-if="!currentUser">
        <div class="login__form">
            <h2>请输入用户名</h2>
            <input type="text" v-model="username" placeholder="用户名" />
            <button @click="register">注册进入聊天</button>
        </div>
    </div>

    <!-- 聊天 -->
    <div v-else style="display: flex; flex-direction: column; height: 100%">
        <header class="chat__header">
            <div class="chat_header_logo">
                <van-icon size="30" name="wechat-moments" />
            </div>

            <div class="chat_header_title">
<!--                <span>聊天室</span>-->
                <span>当前用户：{{ currentUser }}</span>
            </div>

            <div class="chat_header_operation">
                <van-button type="danger" @click="logout" size="small">退出</van-button>

            </div>
        </header>
        <div class="chat__main">
            <div class="chat__sidebar">
                <h3>联系人</h3>
                <div class="chat__userlist">
                    <div v-for="u in users" :key="u"
                         :class="['chat__user', {active: u.username === selectedUser}]"
                         @click="selectUser(u)">
                        <van-badge v-if="u.count > 0" :content="u.count" max="9">
                            {{ u.username }}
                        </van-badge>
                        <span v-else>{{ u.username }}</span>
                    </div>
                </div>
            </div>
            <div class="chat__content">
                <div v-if="selectedUser" class="chat__content_inner">
                    <div class="chat__messages" ref="msgBox">
                        <div v-for="(m, i) in messages" :key="i"
                             :class="['message', m.isSelf ? 'my-message' : 'other-message']">
                            <span>{{ m.text }}</span>
                            <div class="time">{{ m.time }}</div>
                        </div>

                    </div>

                    <form class="chat__input" @submit.prevent="sendMessage">
                        <input type="text" v-model="input" placeholder="输入消息..." />
                        <button type="submit">发送</button>
                    </form>
                </div>

                <div v-else class="chat_content_empty">
                    <div>
                        <van-empty description="开启新对话" />
                    </div>

                    <div class="chat__sidebar-footer">
                        <p class="chat__disclaimer">使用本聊天室服务时，严禁传播任何色情、政治敏感、暴力、恐怖、反动、辱骂、暴恐、低俗等违法违规内容。请自觉遵守法律法规，维护网络环境的清朗与文明。</p>
                        <p class="chat__copyright">© 2025 聊天室 | JintaoYang 版权所有 | 文明交流，共建和谐网络环境</p>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    function fixVH() {
        document.documentElement.style.setProperty('--vh', window.innerHeight * 0.01 + 'px');
    }
    window.addEventListener('resize', fixVH);
    fixVH();

    const socket = io();

    Vue.use(vant);

    new Vue({
        el: '#app',
        data: {
            username: '',
            currentUser: null,
            selectedUser: null,
            users: [{username: '', isCount: 0}],
            messages: [],
            input: ''
        },
        mounted() {
            socket.on('registered', username => {
                this.currentUser = username;
            });
            socket.on('user list', list => {
                console.log(list)
                this.users = list.filter(u => u.username !== this.currentUser);
            });
            socket.on('private message', ({ from, message }) => {
                if (from === this.selectedUser) {
                    this.addMessage(message, false);

                    // 如果是当前选中的用户，则不增加未读计数
                    const user = this.users.find(u => u.username === from);
                    if (user && user.count > 0) {
                        user.count = 0; // 清除未读数
                    }

                } else {
                    // 可添加未读提醒
                    const user = this.users.find(u => u.username === from);
                    if (user) {
                        this.$set(user, 'count', (user.count || 0) + 1); // Vue 的 $set 保证响应性
                    }
                    // 添加到历史记录
                    this.addMessage(message, false, user.username);
                }
            });
            socket.on('error', err => this.$notify(err));

            this.initUser();

        },
        methods: {
            initUser(){
                const chat_self = localStorage.getItem('chat_self');
                if(chat_self) {
                    this.username = chat_self;
                    this.currentUser = chat_self
                    socket.emit('register', this.username);
                }
            },
            register() {
                if (!this.username.trim()) return this.$notify('用户名不能为空');
                socket.emit('register', this.username.trim());
                localStorage.setItem('chat_self', this.username)
            },
            selectUser(user) {
                this.selectedUser = user.username;
                // 清除未读消息数
                const target = this.users.find(u => u.username === user.username);
                if (target && target.count > 0) {
                    target.count = 0;
                }

                // 历史记录存入缓存
                const history = localStorage.getItem('chat_' + user.username);
                if(history) {
                    this.messages = JSON.parse(history)
                }else{
                    this.messages = []
                }

                this.$nextTick(() => {
                    const box = this.$refs.msgBox;
                    box.scrollTop = box.scrollHeight;
                });

            },
            sendMessage() {
                if (!this.input.trim()) return this.$notify({ type: 'warning', message: '消息不能为空' });
                if (!this.selectedUser) return this.$notify({ type: 'warning', message: '请选择联系人' });
                this.addMessage(this.input, true);
                socket.emit('private message', { to: this.selectedUser, message: this.input });
                this.input = '';
            },
            // receiveUser 为未读联系人
            addMessage(msg, isSelf, receiveUser) {
                const time = new Date();
                const pad = n => n.toString().padStart(2, '0');
                const ts = `${time.getFullYear()}-${pad(time.getMonth()+1)}-${pad(time.getDate())} ${pad(time.getHours())}:${pad(time.getMinutes())}:${pad(time.getSeconds())}`;

                // 防止未读消息时遗漏历史记录
                const history = localStorage.getItem('chat_' + (receiveUser ? receiveUser : this.selectedUser));
                if(history) this.messages = JSON.parse(history)
                this.messages.push({ text: msg, isSelf, time: ts });
                localStorage.setItem('chat_' + (receiveUser ? receiveUser : this.selectedUser), JSON.stringify(this.messages));

                this.$nextTick(() => {
                    const box = this.$refs.msgBox;
                    box.scrollTop = box.scrollHeight;
                });
            },
            logout(){
                this.$dialog.confirm({
                    title: '退出登录',
                    message: '确定要退出吗？历史记录将会全部清空！',
                })
                    .then(() => {
                        socket.emit('logout', this.currentUser);
                        this.currentUser = null;
                        localStorage.clear();
                    })
                    .catch(() => {
                        // on cancel
                    })
            }
        }
    });


</script>
</body>
</html>